/*
  1 数组的定义
    内存中一块连续的空间，用于存储一个或多个相同数据类型的数据结构，是一个集合，其内部元素数据类型可以不同
  2 声明数组的5种方式
    2-1 let arr = new Array(10)
      -- arr数组名称
      -- new 创建对象关键字
      -- Array是js内置对象，本质上是一个构造函数
      -- 10定义了数组arr有10个元素
    2-2 let arr = new Array('a',1,2,{})
      -- 'a',1,2,{} 数组的元素
    2-3 let arr = [1,2,3]
      -- 1,2,3是数组元素
    2-4 let arr = Array.of(1,2,3) // [1,2,3]
      -- 使用Array的of函数进行创建数组
      -- 1,2,3是数组的元素
    2-5 let arr = Array.from('foo') // ['f','o','o']
      -- 从其他的数据结构转换成数组
      -- 使用Array的from函数进行创建数组
      -- 'foo'转换为元素['f','o','o']
  3 数组的四要素
    let arr = [1,2,3]
    3-1 名称 arr
    3-2 下标 0,1,2
    3-3 元素 arr[0] arr[1],arr[2]
    3-4 长度 arr.length = 3
  4 数组的属性
    let arr = [1,2,3]
    4-1 下标属性 arr['0']
    4-2 长度属性 arr.length
  5 数组的操作函数
  6 数组的常用算法
*/
const log = console.log
// 1 数组声明1
function fn() {
  // 声明长度10的数组，所有元素都是undefined
  let arr = new Array(10)
  // 对数组元素进行赋值
  arr[0] = 1
  arr[4] = 2
  arr[9] = 3
  // 下标是10的元素,已经是数组的外面,出现数组下标越界
  arr[10] = 4
  // ? 程序是否报错 不报错 数组是一个集合，可以任意扩展长度
  // 如果不报错，数组长度是多少 11
  let len = arr.length
  console.log(len)
  for (let i = 0; i < len; i++) {
    console.log(`arr[${i}] = ${arr[i]}`)
  }
}

// 2 数组声明2
function fn1() {
  let arr = new Array(1, 2, 3)
  // 数组的长度
  let len = arr.length
  console.log('len=' + len) // len=3
  // 遍历数组
  for (let key in arr) {
    console.log(`arr[${key}] = ${arr[key]}`)
  }
}

// 3 数组声明3
function fn2() {
  let arr = [1, 2, 0, , 3, , 6]
  // 数组的长度
  let len = arr.length
  console.log('len=' + len)
  // 遍历数组，使用for-in无法遍历undefined元素
  for (let i = 0; i < len; i++) {
    console.log(`arr[${i}] = ${arr[i]}`)
  }
}

// 4 数组声明4
function fn3() {
  let arr = Array.of(1, 2, 3, 4)
  // 数组的长度
  let len = arr.length
  console.log('len=' + len)
  // 遍历数组，使用for-in无法遍历undefined元素
  for (let i = 0; i < len; i++) {
    console.log(`arr[${i}] = ${arr[i]}`)
  }
}

// 5 数组声明5
function fn4() {
  let arr = Array.from('hello world')
  console.log(arr) // ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
  // 数组的长度
  let len = arr.length
  console.log('len=' + len) // len=11
  // 遍历数组，使用for-in无法遍历undefined元素
  for (let i = 0; i < len; i++) {
    console.log(`arr[${i}] = ${arr[i]}`)
  }
}

// 6 数组元素的添加
function fn6() {
  let arr = [1, 2, 3]
  // 添加到数组的末尾
  arr.push(4)
  console.log(arr) // [1, 2, 3, 4]
  // 添加到首位
  arr.unshift(0)
  console.log(arr) // [0, 1, 2, 3, 4]
}

// 7 数组长度的修改
function fn7() {
  let arr = [1, 2, 3]
  // 修改数组的长度为10
  arr.length = 10
  console.log(arr) // [1, 2, 3, empty × 7]
  // 清空数组
  arr.length = 0
  console.log(arr) // []
}

// 8 数组的at(index)，获得指定index下标位置的元素，如果是负数，从末尾倒序获取
function fn8() {
  let arr = ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
  console.log(arr.at(4)) // 'o'
  console.log(arr.at(-2)) // 倒数第二个元素 'l'
}
// 9 concat([1],[2])合并两个或多个数组
function fn9() {
  let arr = [0, 1, 2]
  // [3, 4]和[5, 6]拼接到arr后
  arr = arr.concat([3, 4], [5, 6])
  console.log(arr) // [0, 1, 2, 3, 4, 5, 6]
}

// 10 copyWithIn(i,j,k) 复制数组的一部分到同一数组中的另一个位置 可以忽略
function fn10() {
  const arr = ['a', 'b', 'c', 'd', 'e']
  let arr1 = arr.copyWithin(0, 3, 5) // 0 被替换的下标，3准备使用的元素下标，就是元素d的下标
  console.log(arr1) // ['d', 'e', 'c', 'd', 'e']
}

// 11 arr.entries() 获得数组的key-value键值对[key,value]
function fn11() {
  const arr = ['a', 'b', 'c', 'd', 'e']
  /*
		let entries = arr.entries() // entries是一个迭代器，不能直接使用for和下标遍历
		for(let item of entries){
			console.log(item)
		}
		console.log(entries)
	*/
  for (let i = 0; i < arr.length; i++) {
    log(`[${i},${arr[i]}]`)
  }
}

// 12 arr.every() 判断数组的元素是否都符合一个条件，返回boolean
function fn12() {
  const arr = [1, 2, 1, 10, 10, 200]
  // 判断数组所有元素是否都大于0，如果都大于0返回true,否则返回false
  let flag = true
  for (let item of arr) {
    if (item <= 0) {
      flag = false
      break
    }
  }
  // log(`flag=${flag}`)
  // 回调函数：函数作为参数使用时，这个函数称回调函数
  // 匿名函数：函数没有名称，但可以执行
  // 箭头函数中的item是数组中每一元素，在底层会自动遍历数组
  let rt = arr.every((item) => item > 0)
  log(`rt=${rt}`)
}

// 普通函数
function add(a, b) {
  log(123)
  return a + b
}
function sub(n) {
  return n
}
// 箭头函数的写法
let add1 = (a, b) => {
  log(123)
  return a + b
}
let sub1 = (n) => n

// 13 arr.fill() 判断数组的元素是否都符合一个条件，返回boolean
function fn13() {
  const arr = new Array(10)
  // arr.fill(1) //  所有的元素都是1
  let start = 2
  let end = 5
  // 从数组的start下标开始填充元素0,到end下标结束，不包括end下标位置
  // [start,end)包头不包尾
  arr.fill(1, start, end)
  log(arr) // [_,_,0,0,0,_,_,_,_,_]
}

// 14 arr.filter() 过滤符合特定条件的元素
function fn14() {
  const arr = [-10, 11, 20, 1, 10, -10, 200]
  // 筛选出>10的元素
  let list = []
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > 10) {
      list.push(arr[i])
    }
  }
  log(list)
  // 使用数组的filter函数
  let arr1 = arr.filter((item) => item > 10)
  log(arr1)
}

// 15 arr.find() 找第一个符合条件的元素
function fn15() {
  const arr = [-10, 11, 20, 1, 10, -10, 200]
  // 找第一个大于10的元素
  let el = undefined
  let s = 3
  let e = arr.length
  for (let i = s; i < e; i++) {
    if (arr[i] > 10) {
      el = arr[i]
      break
    }
  }
  log(el) // 200
  let element = arr.find((item) => item > 10)
  log(element) // 11
}

// 16 arr.findIndex() 找到第一个符合条件的元素下标,如果找不到返回-1
function fn16() {
  const arr = [10, 11, 20, 11, 10, 100, 200]
  // 找第一个小于10元素下标
  let index = -1
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < 10) {
      // i就是下标
      index = i
      break
    }
  }
  if (index !== -1) {
    log(index, arr[index])
  } else {
    log('你要找的元素不存在')
  }

  let i = arr.findIndex(function (item) {
    return item < 10
  })
  if (i !== -1) {
    log(i, arr[i])
  } else {
    log('你要找的元素不存在')
  }
}

// 17 arr.findLast() 找数组最后符合条件的元素
function fn17() {
  const arr = [5, 12, 50, 130, 44]
  let element = undefined
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i] > 45) {
      element = arr[i]
      break
    }
  }
  log(element)

  let el = arr.findLast((item) => item > 45)
  log(el)
}

// 18 arr.findLastIndex() 从数组后面向前找第一符合条件的元素的下标
function fn18() {
  const arr = [5, 12, 130, 50, 44]
  let index = -1
  for (let i = arr.length - 1; i >= 0; i--) {
    if (arr[i] > 45) {
      index = i
      break
    }
  }
  log(index, arr[index]) // 3 50

  let index1 = arr.findLastIndex((it) => it > 45)
  log(index1, arr[index1]) // 3 50
}

// 19 arr.flat() 数组扁平化，把多维数组转换为一维数组 [1,[2,3,[4,5,[6,7]]],[8,9]] --> [1,2,3,[4,5,[6,7]],8,9]
let arr = [1, [2, 3, [4, 5, [6, 7]]], [8, 9]]
let list = []
function fn19(arr) {
  // 判断数组arr是否是数组
  /*if(Array.isArray(arr)){
		for(let i =0;i<arr.length;i++){
			fn19(arr[i])
		}
	}else{
		list.push(arr)
	}*/

  /*if(!Array.isArray(arr)){
		return list.push(arr)
	}
	for(let i =0;i<arr.length;i++){
		fn19(arr[i])
	}*/
  if (!Array.isArray(arr)) {
    return list.push(arr)
  }
  // item是数组的元素，forEach是数组的元素遍历函数
  arr.forEach((item) => fn19(item))
}
// fn19(arr)
// log(list)

// 给数组对象添加一个自定义的方法，所有的数组都可使用这个方法
/*Array.prototype.flatAll = function() {
	let arr = this
	if(!Array.isArray(arr)){
		return list.push(arr)
	}
	arr.forEach(function(item){
		if(!Array.isArray(item)){
			return list.push(item)
		}
		item.flatAll()
	})
}

arr.flatAll()
log(list)
list = []
let array = ['a','b',['c',['d']]]
array.flatAll()
log(list)*/

// 20 arr.flatMap() 类似flat,只不过效率高，原因是底层使用的是map集合
function fn20() {
  let arr = ['a', 'b', ['c', ['d']]]
  log(arr.flatMap((item) => item)) // ['a', 'b', 'c', ['d']
}

// 21 arr.forEach() 对数组元素进行遍历
function fn21() {
  const arr = [5, 12, 130, 50, 44]
  // it 是元素，i是下标
  arr.forEach((it, i) => {
    log(i, it)
  })
  // $.each(arr,(i,item)=>{ log(i, it) })
}

// 22 arr.includes() 判断数组是否包含此元素
let fn22 = () => {
  const arr = [5, 12, 130, 50, 44]
  let rt = arr.includes(50)
  log(rt) // true
}

// 23 arr.indexOf(el) 返回arr中el首次出现的下标
let fn23 = () => {
  const arr = [5, 12, 130, 12, 50, 44]
  let index = arr.indexOf(12)
  log(index, arr[index]) // 1 12
}

// 24 Array.isArray(args) 判断args是否是数组
let fn24 = () => {
  const arr = new Array() // [5, 12, 130, 12, 50, 44]
  let rt = Array.isArray(arr)
  log(rt) // true
}

// 25 arr.join(',') 使用指定的字符把数组转换为字符串
let fn25 = () => {
  const arr = [5, 12, 130, 12, 50, 44]
  let str = arr.join(',') // 5,12,130,12,50,44
  log(str)
}

// 26 arr.keys() 获得数组的所有下标迭代器
let fn26 = () => {
  const arr = [5, 12, 130, 12, 50, 44]
  let keys = arr.keys()
  for (let item of keys) {
    log(item, arr[item])
    /*
		0 5
		1 12
		2 130
		3 12
		4 50
		5 44*/
  }
}

// 27 arr.lastIndexOf(2) 最后一次出现元素2的下标,如果没有找到返回-1
let fn27 = () => {
  const arr = [5, 12, 130, 12, 50, 44]
  let index = arr.lastIndexOf(12)
  log(index, arr[index]) // 3 12
}

// 28 arr.map(function(item){ return item})  方法创建一个新数组,数组的元素是回调函数的返回值
let fn28 = () => {
  const arr = [5, 12, 130, 12, 50, 44]
  let list = arr.map((item) => item ** 2)
  log(list) // [ 25, 144, 16900, 144, 2500, 1936 ]
  // let array = []
  // for (let i = 0; i < arr.length; i++) {
  //   array.push(arr[i] * 2)
  // }
  // log(array)
  let array = arr.map((y) => y * 2)
  log(array) // [ 10, 24, 260, 24, 100, 88 ]
}

// 29 arr.pop() 删除数组中最后一个元素
let fn29 = () => {
  const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato']
  plants.pop()
  log(plants) // [ 'broccoli', 'cauliflower', 'cabbage', 'kale' ]
}

// 30 arr.push() 方法将一个或多个元素添加到数组的末尾，并返回该数组的新长度
let fn30 = () => {
  const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato']
  let len = plants.push('fish')
  log(len, plants)
}

// 31 arr.reduce() 收敛函数
let fn31 = () => {
  const arr = [50, 10, 10, 10, 50, 40]
  let rt = arr.reduce((prev, next) => {
    return prev + next
  })
  log(rt) // 170
}

// 32 arr.reduceRight() 数组从右开始收敛
let fn32 = () => {
  const array = [
    [0, 1], // [4,5,2,3,0,1]
    [2, 3], // [4,5,2,3]
    [4, 5],
  ]
  let list = array.reduceRight((prev, next) => prev.concat(next))
  console.log(list) // [ 4, 5, 2, 3, 0, 1 ]
}

// 33 arr.reverse() 数组反转
let fn33 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  arr.reverse()
  console.log(arr) // [ 1, 0, 3, 2, 5, 4 ]
}

// 34 arr.shift() 删除第一个元素
let fn34 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  arr.shift() // [ 5, 2, 3, 0, 1 ]
  log(arr)
}

// 35 arr.slice(s,e) 截取数组从s位置开始到e位置的元素，不包括e
let fn35 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  let list = arr.slice(2, 4) // [2,3]
  log(list)
}

// log('hello'.split('').reverse().join('')) // olleh 字符串反转

// 36 arr.some() 方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试
let fn36 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  let rt = arr.some((x) => x > 10) // false
  log(rt) // false
}

// 37 arr.sort() 数组排序
let fn37 = () => {
  let arr = [4, 5, 2, 3, 0, 1]
  // 冒泡排序
  // let n = arr.length
  // for (let i = 0; i < n - 1; i++) {
  //   for (let j = 0; j < n - i - 1; j++) {
  //     if (arr[j] < arr[j + 1]) {
  //       let t = arr[j]
  //       arr[j] = arr[j + 1]
  //       arr[j + 1] = t
  //     }
  //   }
  // }
  // p-n升序 n-p是降序
  arr.sort((p, n) => n - p)
  log(arr) // [ 0, 1, 2, 3, 4, 5 ]
}

// 38 arr.splice(index,1,1,2,3) 在数组的index下标位置删除1个元素，并在此处插入元素1，2，3
let fn38 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  let index = arr.findIndex((item) => item === 0)
  if (index !== -1) {
    arr.splice(index, 1, 'a', 'b') //[ 4, 5, 2, 3, 'a','b', 1 ]
  }
  log(arr)
}

// 39 toLocalString() toString()
let fn39 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  log(arr.toLocaleString(), arr.toString()) // 4,5,2,3,0,1     4,5,2,3,0,1
}

// 40 unshift() 添加index=0的元素,返回新数组的长度
let fn40 = () => {
  let arr = [4, 5, 2, 3, 0, 1]
  let len = arr.unshift(6)
  log(arr, '-------', len)
  // [
  // 	6, 4, 5, 2,
  // 	3, 0, 1
  // ] ------- 7
}

// 41 arr.values() 获得数组元素的迭代器
let fn41 = (n) => {
  let arr = [4, 5, 2, 3, 0, 1]
  let iterator = arr.values()
  for (let value of iterator) {
    log(value)
  }
}
fn41()
